package cn.gx.kevin.common.utils;

import com.alibaba.fastjson.JSONObject;
import cn.gx.kevin.common.ui.AdminControllerHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @Description: 参数URLDecode
 * @date 2016年9月21日 下午1:50:21
 * @version v1.0.0
 *
 */
public class ParameterRequestWrapper extends HttpServletRequestWrapper {

	public final Logger logger = org.slf4j.LoggerFactory.getLogger(ParameterRequestWrapper.class);

	private Map<String, String[]> params = new HashMap<String, String[]>();

	public ParameterRequestWrapper(HttpServletRequest request, Map<String, String[]> newParams) {
		super(request);
		renewParameterMap(request);
	}

	public  String decodeReplacer(String str) {
		String data = str;
		try {
			data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
			data = data.replaceAll("\\+", "%2B");
			data = URLDecoder.decode(data, "utf-8");
		} catch (Exception e) {
			logger.error("",e);
		}
		return data;
	}

	@Override
	public String getParameter(String name) {
		String result = "";
		Object v = params.get(name);
		if (v == null) {
			result = null;
		} else if (v instanceof String[]) {
			String[] strArr = (String[]) v;
			if (strArr.length > 0) {
				result = strArr[0];
			} else {
				result = null;
			}
		} else if (v instanceof String) {
			result = (String) v;
		} else {
			result = v.toString();
		}
		return result;
	}

	@Override
	public Map<String, String[]> getParameterMap() {
		return params;
	}

	@Override
	public Enumeration<String> getParameterNames() {
		return new Vector<String>(params.keySet()).elements();
	}

	@Override
	public String[] getParameterValues(String name) {
		String[] result = null;
		Object v = params.get(name);
		if (v == null) {
			result = null;
		} else if (v instanceof String[]) {
			result = (String[]) v;
		} else if (v instanceof String) {
			result = new String[] { (String) v };
		} else {
			result = new String[] { v.toString() };
		}
		return result;
	}

	private void renewParameterMap(HttpServletRequest request) {
		String method = request.getMethod();
		if (method.equalsIgnoreCase("get")) {// 解决中文乱码问题
			// 取出客户提交的参数集
			Enumeration<String> paramNames = request.getParameterNames();
			// 遍历参数集取出每个参数的名称及值
			while (paramNames.hasMoreElements()) {
				String name = paramNames.nextElement(); // 取出参数名称
				String values[] = request.getParameterValues(name); // 根据参数名称取出其值
				// 如果参数值集不为空
				if (values != null) {
					// 遍历参数值集
					for (int i = 0; i < values.length; i++) {
						try {
							String v = values[i];// URLDecoder.decode(values[i],"utf-8");
							String vlustr = new String(v.getBytes("iso-8859-1"), "UTF-8");
							values[i] = cleanXSS(vlustr);
						} catch (UnsupportedEncodingException e) {
							e.printStackTrace();
						}
					}
					this.params.put(name, values);
				}
			}
		} else {// 对post的参数进行统一urldecode
			String contentType = request.getContentType();
			Map<String, String[]> parameters = request.getParameterMap();
			// System.out.println(contentType +" parameters = " +parameters.size());
			/***** 适配axois 请求，将axois的参数提取到this.params ********/
			if (contentType != null && contentType.contains("application/json") && parameters.size() == 0) {
				StringBuilder sb = new StringBuilder();
				try {
					BufferedReader reader = request.getReader();
					char[] buff = new char[1024];
					int len;
					while ((len = reader.read(buff)) != -1) {
						sb.append(buff, 0, len);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				String json = sb.toString();
				if (StringUtils.isNotEmpty(json)) {
					Map<String, String> tmpParams = JSONObject.parseObject(json, Map.class);
					for (Map.Entry<String, String> entry : tmpParams.entrySet()) {
						String value = String.valueOf( entry.getValue());
						this.params.put(entry.getKey(), new String[] { cleanXSS(value) });
					}
				}
				this.params.put(SysConstants.postFormJson, new String[] { json });
			}
			String notDecode = request.getParameter("_not_url_decode_");
			Set<String> keys = parameters.keySet();
			for (String key : keys) {
				String[] values = parameters.get(key);
				for (int i = 0; i < values.length; i++) {
						if (StringUtils.isNotEmpty(notDecode) || "token".equals(key)) {
							values[i] = cleanXSS(values[i]);
						} else {
							String  data = values[i];
							data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
							data = data.replaceAll("\\+", "%2B");
							values[i] = cleanXSS(AdminControllerHelper.urlDecoder(data));
						}
				}
				this.params.put(key, values);
			}
		}

	}


	/**
	 * 将容易引起xss & sql漏洞的半角字符直接替换成全角字符
	 *
	 * @param s
	 * @return
	 */
	private static String xssEncode(String s) {
		if (s == null || s.isEmpty()) {
			return s;
		}else{
			s = cleanXSS(s);
		}
		StringBuilder sb = new StringBuilder(s.length() + 16);
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			switch (c) {
				case '>':
					sb.append("＞");// 转义大于号
					break;
				case '<':
					sb.append("＜");// 转义小于号
					break;
				case '\'':
					sb.append("＇");// 转义单引号
					break;
				case '\"':
					sb.append("＂");// 转义双引号
					break;
				case '&':
					sb.append("＆");// 转义&
					break;
				case '#':
					sb.append("＃");// 转义#
					break;
				default:
					sb.append(c);
					break;
			}
		}
		return sb.toString();
	}

	private static String cleanXSS(String value) {
		if (value != null) {
			// NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to
			// avoid encoded attacks.
			// value = ESAPI.encoder().canonicalize(value);
			// Avoid null characters
			//value = value.replaceAll("", "");
			// Avoid anything between script tags
			Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
			value = scriptPattern.matcher(value).replaceAll("");
			// Avoid anything in a src="..." type of e­xpression
			/*
			 * scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
			 * Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value =
			 * scriptPattern.matcher(value).replaceAll("");
			 */
			// Remove any lonesome </script> tag
			scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
			value = scriptPattern.matcher(value).replaceAll("");
			// Remove any lonesome <script ...> tag
			scriptPattern =
					Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
			value = scriptPattern.matcher(value).replaceAll("");
			// Avoid eval(...) e­xpressions
			scriptPattern =
					Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
			value = scriptPattern.matcher(value).replaceAll("");
			// Avoid e­xpression(...) e­xpressions
			scriptPattern = Pattern.compile("e­xpression\\((.*?)\\)",
					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
			value = scriptPattern.matcher(value).replaceAll("");
			// Avoid javascript:... e­xpressions
			scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
			value = scriptPattern.matcher(value).replaceAll("");
			// Avoid vbscript:... e­xpressions
			scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
			value = scriptPattern.matcher(value).replaceAll("");
			// Avoid onload= e­xpressions
			scriptPattern =
					Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
			value = scriptPattern.matcher(value).replaceAll("");

			// Avoid onerror= e­xpressions
			scriptPattern =
					Pattern.compile("onerror(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);

			value = scriptPattern.matcher(value).replaceAll("");
			value = value.replaceAll(
					"(window\\.location|window\\.|\\.location|document\\.cookie|document\\.|alert\\(.*?\\)|window\\.open\\()*",
					"");
		}
		return value;
	}
}